#include "widget.h"
#include "ui_widget.h"
#include "encode.cpp"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    // 实例化托盘图标
    tray = new QSystemTrayIcon(this);
    tray->setToolTip("OprtCtrl-受控端");
    tray->setIcon(QIcon(":/res/tray.png"));
    connect(tray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(show()));

    QString conn = getIP();
    if(conn.isEmpty()) {
        QMessageBox box;
        box.setText(tr("请插入网络设备！"));
        box.exec();
        exit(-1);
    }

    // 创建UDP对象
    udpSocket=new QUdpSocket(this);
    localAddr = new QHostAddress(conn);

    for(udpLocalPort = 6666; udpLocalPort < 6688; udpLocalPort++)
    {
        if(udpSocket->bind(*localAddr,udpLocalPort)) {
            break;
        }
    }
    if(udpLocalPort >= 6688)
    {
        QMessageBox box;
        box.setText(tr("网络监听失败！"));
        box.exec();
        exit(-1);
    }
    else
    {
        connect(udpSocket,SIGNAL(readyRead()),this,SLOT(receive()));
        if(encode((conn + "," +  QString::number(udpLocalPort)).toStdString().c_str()))
        {
            showQR();
        }
        else
        {
            QMessageBox box;
            box.setText(tr("网络连接失败！"));
            box.exec();
            exit(-1);
        }
    }
}

void Widget::showQR()
{
    QImage *qr = new QImage("test.bmp");
    ui->label->setPixmap(QPixmap::fromImage(*qr, Qt::AutoColor));
}

void Widget::receive()
{
    while(udpSocket->hasPendingDatagrams()){ //是否读到数据
        QByteArray data;
        // udpSocket->pendingDatagramSize 获取报文长度
        // data.resize 给 data 数组设置长度
        data.resize(udpSocket->pendingDatagramSize());
        // 读入数据
        udpSocket->readDatagram(data.data(),data.size());
        // 显示数据内容
        QString str=data.data();
        int a[] = {-1};
        if(str.at(0) == '0') //鼠标位移指令
        {
            bool ok = true;
            int xAcc = str.mid(2).split(",").at(0).toInt(&ok,10);
            int yAcc = str.mid(2).split(",").at(1).toInt(&ok,10);
            if(ok)
            {
                QCursor *cur = new QCursor;
                moveCursor(cur, xAcc, -yAcc);
            }
        }
        else if(str.at(0) == '1')
        {
            // 具体操作含义，请参考mouseCtrl函数
            mouseCtrl(str.at(2).unicode() - '0');
        }
        else if(str.at(0) == '2') //幻灯片操作指令 如 2,F
        {
            switch (str.at(2).unicode())
            {
            case 'F': // 幻灯片开始播放
                a[0] = VK_F5;
                sendKey(a, 1);
                break;
            case 'P': // 上一张幻灯片
                a[0] = VK_UP;
                sendKey(a, 1);
                break;
            case 'N': // 下一张幻灯片
                a[0] = VK_DOWN;
                sendKey(a, 1);
                break;
            case 'W': // 进入/退出白屏
                a[0] = 0x57;
                sendKey(a, 1);
                break;
            case 'B': // 进入/退出黑屏
                a[0] = 0x42;
                sendKey(a, 1);
                break;
            case 'Q': // 退出演示
                a[0] = VK_ESCAPE;
                sendKey(a, 1);
                break;
            case 'H': // 切到第一张
                a[0] = VK_HOME;
                sendKey(a, 1);
                break;
            case 'E': // 切到最后一张
                a[0] = VK_END;
                sendKey(a, 1);
                break;
            }
        }
        else if(str.at(0) == '3') //其他指令 如 3,B
        {
            switch (str.at(2).unicode())
            {
            case 'B': // 受控开始，自动隐藏窗体到托盘
                tray->show();
                hide();
                break;
            case 'S': // 打开网页浏览器……可以进一步自行扩展
                a[0] = 0xAC;
                sendKey(a, 1);
                break;
            }
        }
    }
}

/*
 * 控制光标在单位时间内移动
 * cur: 光标实例
 * xAcc: 水平方向加速度
 * yAcc: 垂直方向加速度
 */
void Widget::moveCursor(QCursor *cur, int xAcc, int yAcc)
{
    int x,y;
    x = cur->pos().x() - xAcc;
    y = cur->pos().y() - yAcc;
    if(x > W)
        x = W;
    if(y > H)
        y = H;
    cur->setPos(x,y);
}

/*
 * 利用 Windows API 向系统送模拟按键
 * keys: 有序的组合键数组
 * n: 数组长度
 * 键码对应关系: msdn.microsoft.com/en-us/library/windows/desktop/dd375731%28v=vs.85%29.aspx
 */
void Widget::sendKey(int keys[], int n)
{
    int i;
    INPUT *ip = new INPUT[n];
    for(i = 0; i < n; ++i)
    {
        ip[i].type = INPUT_KEYBOARD;
        ip[i].ki.wScan = 0;
        ip[i].ki.time = 0;
        ip[i].ki.dwExtraInfo = 0;
        ip[i].ki.dwFlags = 0; // 按下
        ip[i].ki.wVk = keys[i];
        SendInput(1, &ip[i], sizeof(INPUT));
    }
    for(i = n-1; i >= 0; --i)
    {
        ip[i].ki.dwFlags = KEYEVENTF_KEYUP; // 释放
        SendInput(1, &ip[i], sizeof(INPUT));
    }
    delete [] ip;
}

/*
 * 利用 Windows API 向系统送鼠标操作
 * type: 操作类型
 * 键码对应关系: msdn.microsoft.com/en-us/library/windows/desktop/ms646273(v=vs.85).aspx
 */
void Widget::mouseCtrl(int type)
{
    INPUT ip;
    ip.type = INPUT_MOUSE;
    if(type == 6 || type == 9) //向下（上）滚动6（9）
    {
        ip.mi.dwFlags = MOUSEEVENTF_WHEEL;
        ip.mi.mouseData = (type==6) ? WHEEL_DELTA : -WHEEL_DELTA;
        SendInput(1, &ip, sizeof(INPUT));
        return;
    }
    else
    {
        switch (type)
        {
        case 2: // 右键单击
            ip.mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;
            SendInput(1, &ip, sizeof(INPUT));
            ip.mi.dwFlags = MOUSEEVENTF_RIGHTUP;
            SendInput(1, &ip, sizeof(INPUT));
            break;
        case 3: // 中键单击
            ip.mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN;
            SendInput(1, &ip, sizeof(INPUT));
            ip.mi.dwFlags = MOUSEEVENTF_MIDDLEUP;
            SendInput(1, &ip, sizeof(INPUT));
            break;
        case 1: // 左键按下
            ip.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
            SendInput(1, &ip, sizeof(INPUT));
            break;
        case 0: // 左键释放
            ip.mi.dwFlags = MOUSEEVENTF_LEFTUP;
            SendInput(1, &ip, sizeof(INPUT));
            break;
        default: // 左键单击8
            ip.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
            SendInput(1, &ip, sizeof(INPUT));
            ip.mi.dwFlags = MOUSEEVENTF_LEFTUP;
            SendInput(1, &ip, sizeof(INPUT));
            break;
        }
    }
}

QString Widget::getIP()
{
    QList<QHostAddress> list = QNetworkInterface::allAddresses();
    foreach(QHostAddress address, list)
    {
        // 遍历IP地址并编码WiFi热点信息为二维码
        if(address.protocol() == QAbstractSocket::IPv4Protocol && address.toString().contains("172.27.35"))
        {
            return address.toString();
        }
    }
    return "";
}

Widget::~Widget()
{
    delete ui;
}
